﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;

using Testing.DataService;
using Testing.DataService.Entities;
using Testing.DataService.Mock;
using Testing.DataService.Repositories;
using Testing.DataService.Repositories.Interfaces;

using Testing.IntegrationTests.Filters;

using System.Data.Entity.Repository.Filters;
using System.Diagnostics;
using System.Threading.Tasks;

namespace Testing.IntegrationTests
{
    [TestClass]
    public class PerformanceTestWithFind
    {
        private Testing.DataService.Repositories.Interfaces.IProductRepository _productRepository;
        List<Product> mockProducts;

        [TestInitialize]
        public void TestInitialize()
        {
            _productRepository = new ProductRepository();
        }

        [TestMethod]
        public void IntegrationTest_Transaction_FindSingleProductWithWhere()
        {
            Stopwatch sw = new Stopwatch();
            List<Product> result;

            RegisterableFilter filter = new RegisterableFilter
            {
                FilterInstance = new ProductFilterNumber2(),
                ParameterBag = null
            };
            QueryableFilterManager.Register(filter);

            startMockup(3);

            sw.Start();
            {
                 result = _productRepository.Find<Product>(x => x.ProductName == "Duvel Green 2")
                    .ToList();
            }
            sw.Stop();

            cleanupMockup();

            //breakepoint here
            TimeSpan duration = sw.Elapsed;

            Assert.IsNotNull(result);
        }

        [TestMethod]
        public void IntegrationTest_Transaction_FindSingleProductWithFilter()
        {
            Stopwatch sw = new Stopwatch();
            List<Product> result;

            RegisterableFilter filter = new RegisterableFilter
            {
                FilterInstance = new ProductFilterNumber2(),
                ParameterBag = null
            };
            QueryableFilterManager.Register(filter);

            startMockup(3);

            sw.Start();
            {
                result = _productRepository.Find<Product>(x => x.ProductName == "Duvel Green 2")
                   .ToList();
            }
            sw.Stop();

            cleanupMockup();

            //breakepoint here
            TimeSpan duration = sw.Elapsed;

            Assert.IsNotNull(result);
        }

        [TestMethod]
        public void IntegrationTest_Transaction_FindProductsThatContains2WithFilter_WithoutInsert()
        {
            Stopwatch sw = new Stopwatch();
            List<Product> products;

            RegisterableFilter filter = new RegisterableFilter
            {
                FilterInstance = new ProductFilterNumber2(),
                ParameterBag = null
            };

            dynamic pagingBag = new {
                Skip = 2,
                Take = 2
            };

            RegisterableFilter pagingFilter = new RegisterableFilter
            {
                FilterInstance = new PagingFilter(),
                ParameterBag = pagingBag
            };

            QueryableFilterManager.Register(pagingFilter);

            sw.Start();
            {
                IQueryable<Product> entities = _productRepository.GetAll<Product>()
                .AsQueryable();

                var filteredResult = entities.FilterWith<IProductFilter, Product>();

                products = filteredResult.ToList();
            }
            sw.Stop();

            //breakepoint here
            TimeSpan duration = sw.Elapsed;

            Assert.IsNotNull(products);
        }

        [TestMethod]
        public void IntegrationTest_Transaction_FindProductsThatContains2WithFilter_WithInsert()
        {
            Stopwatch sw = new Stopwatch();
            List<Product> products;

            RegisterableFilter filter = new RegisterableFilter
            {
                FilterInstance = new ProductFilterNumber2(),
                ParameterBag = null
            };
            QueryableFilterManager.Register(filter);

            startMockup(5000);

            sw.Start();
            {
                IQueryable<Product> entities = _productRepository.GetAll<Product>()
                .AsQueryable();

                var filteredResult = entities.FilterWith<IProductFilter, Product>();

                products = filteredResult.ToList();
            }
            sw.Stop();

            cleanupMockup();

            //breakepoint here
            TimeSpan duration = sw.Elapsed;

            Assert.IsNotNull(products);
        }

        [TestMethod]
        public void IntegrationTest_Transaction_FindProductsThatContains2WithWhere_WithoutInsert()
        {
            Stopwatch sw = new Stopwatch();
            List<Product> products;

            sw.Start();
            {
                IQueryable<Product> entities = _productRepository.Find<Product>(x => x.ProductName.Contains("2"))
                    .AsQueryable();

                var filteredResult = entities.FilterWith<IProductFilter, Product>();

                products = filteredResult.ToList();
            }
            sw.Stop();

            //breakepoint here
            TimeSpan duration = sw.Elapsed;

            Assert.IsNotNull(products);
        }

        [TestMethod]
        public void IntegrationTest_Transaction_FindProductsThatContains2WithWhere_WithInsert()
        {
            Stopwatch sw = new Stopwatch();
            List<Product> products;

            RegisterableFilter filter = new RegisterableFilter
            {
                FilterInstance = new ProductFilterNumber2(),
                ParameterBag = null
            };
            QueryableFilterManager.Register(filter);

            startMockup(5000);
            sw.Start();
            {
                IQueryable<Product> entities = _productRepository.Find<Product>(x => x.ProductName.Contains("2"))
                    .AsQueryable();

                var filteredResult = entities.FilterWith<IProductFilter, Product>();

                products = filteredResult.ToList();
            }
            sw.Stop();

            //breakepoint here
            TimeSpan duration = sw.Elapsed;

            cleanupMockup();

            Assert.IsNotNull("1");
        }

        private void startMockup(int numberOfProducts)
        {
            Task[] tasks = new Task[1];

            //insert test data
            tasks[0] = Task.Factory.StartNew(() =>
            {
                mockProducts = new MockProduct()
                    .CreateMultipleProductsInList(numberOfProducts);

                _productRepository.AddMultipleProductsWithCommit(mockProducts);

            });
            Task.WaitAll(tasks);
        }

        private void cleanupMockup()
        {
            Task[] tasks = new Task[1];

            tasks[0] = Task.Factory.StartNew(() =>
            {
                _productRepository.DeleteMultipleWithCommit(mockProducts);
            });
            Task.WaitAll(tasks);
        }

        [TestCleanup]
        public void TestCleanup()
        {
            _productRepository.Dispose();
        }
    }
}
